#include <iostream>
#include "Sock.hpp"
#include "Protocol.hpp"
 
using namespace ns_protocol;
 
// 输出程序使用说明的辅助函数
static void Usage(const std::string &process)
{
    std::cout << "\nUsage: " << process << " serverIp serverPort\n"
              << std::endl;
}
 
// 客户端主函数，接收命令行参数并与服务器建立连接进行交互
int main(int argc, char *argv[])
{
    if (argc != 3) // 检查参数数量
    {
        Usage(argv[0]); // 参数不正确时输出使用说明
        exit(1); // 退出程序
    }
 
    std::string server_ip = argv[1]; // 获取服务器IP地址
    uint16_t server_port = atoi(argv[2]); // 获取服务器端口号
 
    Sock sock; // 创建Socket对象
    int sockfd = sock.Socket(); // 创建套接字
 
    if (!sock.Connect(sockfd, server_ip, server_port)) // 连接到服务器
    {
        std::cerr << "Connect error" << std::endl;
        exit(2); // 连接失败时退出程序
    }
 
    bool quit = false; // 标记是否退出循环
    std::string buffer; // 用于临时存储接收的数据
 
    while (!quit) // 循环接收用户输入并发送计算请求，直到用户选择退出
    {
        // 1. 获取用户输入的计算需求
        Request req;
        std::cout << "Please Enter # ";
        std::cin >> req.x_ >> req.op_ >> req.y_; // 读取操作数和运算符
 
        // 2. 序列化请求对象，将结构化数据转换为字符串
        std::string s = req.Serialize();
 
        // 3. 添加长度报头，形成完整请求报文
        s = Encode(s);
 
        // 4. 将请求报文发送给服务器
        Send(sockfd, s);
 
        // 5. 接收服务器响应
        while (true)
        {
            bool res = Recv(sockfd, &buffer); // 从套接字接收数据
            if (!res)
            {
                quit = true; // 收到错误信号时退出循环
                break;
            }
 
            std::string package = Decode(buffer); // 解码接收到的数据，获取完整响应报文
            if (package.empty()) // 若未接收到完整报文，则继续接收
                continue;
 
            Response resp; // 创建响应对象
            resp.Deserialized(package); // 反序列化响应报文，填充响应对象
 
            std::string err; // 存储可能的错误消息
            switch (resp.code_) // 根据响应中的错误代码判断计算结果
            {
            case 1: // 除0错误
                err = "除0错误";
                break;
            case 2: // 模0错误
                err = "模0错误";
                break;
            case 3: // 非法操作
                err = "非法操作";
                break;
            default: // 计算成功
                std::cout << resp.x_ << resp.op_ << resp.y_ << " = " << resp.result_ << " [success]" << std::endl;
                break;
            }
 
            if (!err.empty()) // 如果有错误消息，则输出错误信息
                std::cerr << err << std::endl;
 
            // sleep(1); // 原代码注释掉了此行，若需要暂停一段时间再接收下一个请求可取消注释
 
            break; // 接收完一个完整响应后跳出内部循环
        }
    }

    close(sockfd); // 关闭套接字
    return 0; // 程序正常结束
}